package com.swak.telnet.cmd;

import java.lang.reflect.Method;

import org.springframework.util.Assert;

import com.swak.annotation.Cmd;
import com.swak.exception.FluxInvokeException;

public class CmdInvoker {

	final Object handler;
	final Cmd cmd;
	final Method method;

	public CmdInvoker(Object handler) {
		this.handler = handler;
		this.cmd = handler.getClass().getAnnotation(Cmd.class);
		this.method = this.resolveMethod();
		Assert.isTrue(this.cmd != null, "please use @Cmd on Class:" + handler.getClass().getCanonicalName());
		Assert.isTrue(this.method != null,
				"no method named " + this.cmd.method() + " in Class:" + handler.getClass().getCanonicalName());
	}

	private Method resolveMethod() {
		try {
			return handler.getClass().getDeclaredMethod(cmd.method(), Command.class);
		} catch (Exception e) {
		}
		return null;
	}

	public Object doInvoke(Command request) {
		try {
			return method.invoke(handler, request);
		} catch (Exception e) {
			RuntimeException error = new FluxInvokeException(
					String.format("Failed to Invoke [Service:{%s} - Method: {%s}].", handler.getClass().getName(),
							method.getName()),
					e.getCause() != null ? e.getCause() : e);
			throw error;
		}
	}

	public String getCommand() {
		return this.cmd.name();
	}

	public String getSummary() {
		return this.cmd.summary();
	}

	public String[] getExample() {
		return this.cmd.example();
	}

	public static CmdInvoker of(Object handler) {
		return new CmdInvoker(handler);
	}
}
